﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OS.Instructions
{
    class Instruction
    {
        private bool isValid;
        private String theInstruction;
        private String memoryLocation;
        private Dictionary<string, Instruction> validInstructions = new Dictionary<string,Instruction>();

        public const int BLOCK_SIZE = 10;

        public bool IsValid
        {
            get { return isValid; }
            set { isValid = value; }
        }

        public String TheInstruction
        {
            get { return theInstruction; }
            set { theInstruction = value; }
        }

        public String MemoryLocation
        {
            get { return memoryLocation; }
            set { memoryLocation = value; }
        }

        public Dictionary<String, Instruction> ValidInstructions
        {
            get { return validInstructions; }
            set { validInstructions = value; }
        }
        public Instruction() { }

        public Instruction(String instr)
        {
            validInstructions.Add("LR", new LoadRegister());
            validInstructions.Add("SR", new StoreRegister());
            validInstructions.Add("CR", new CompareRegister());
            validInstructions.Add("BT", new BranchOnTrue());
            validInstructions.Add("GD", new GetData());
            validInstructions.Add("PD", new PrintData());
            validInstructions.Add("H ", new Halt());

            if (instr.Length == 4)
            {
                this.theInstruction = instr.Substring(0, 2);
                this.memoryLocation = instr.Substring(2, 2);
            }
            else if (instr.Length == 5)
            {
                this.theInstruction = instr.Substring(0, 2);
                this.memoryLocation = instr.Substring(2, 3);
            }
            else
            {
                this.theInstruction = null;
                this.memoryLocation = null;
            }
        }

        public void InitInstructions()
        {
            validInstructions = new Dictionary<String, Instruction>();

            validInstructions.Add("LR", new LoadRegister());
            validInstructions.Add("SR", new StoreRegister());
            validInstructions.Add("CR", new CompareRegister());
            validInstructions.Add("BT", new BranchOnTrue());
            validInstructions.Add("GD", new GetData());
            validInstructions.Add("PD", new PrintData());
            validInstructions.Add("H",  new Halt());
        }

        public void ExecuteInstruction()
        {
            int num;

            if (!this.theInstruction.Equals("H ") && !int.TryParse(this.memoryLocation, out num))
            {
                Trace.WriteToTrace("Invalid operand, PI <- 2");
                CPU.PI = 2;
                return;
            }

            if (this.GetType().Equals(typeof(BranchOnTrue)))
            {
                this.ExecuteBTInstruction();
            }
            else if (this.GetType().Equals(typeof(CompareRegister)))
            {
                this.ExecuteCRInstruction();
            }
            else if (this.GetType().Equals(typeof(GetData)))
            {
                this.ExecuteGDInstruction();
            }
            else if (this.GetType().Equals(typeof(Halt)))
            {
                this.ExecuteHInstruction();
            }
            else if (this.GetType().Equals(typeof(LoadRegister)))
            {
                this.ExecuteLRInstruction();
            }
            else if (this.GetType().Equals(typeof(PrintData)))
            {
                this.ExecutePDInstruction();
            }
            else if (this.GetType().Equals(typeof(StoreRegister)))
            {
                this.ExecuteSRInstruction();
            }
            else
            {
                //abort due to invalid operation
            }
        }

        public virtual void ExecuteBTInstruction()
        {
        }

        public virtual void ExecuteCRInstruction()
        {
        }

        public virtual void ExecuteGDInstruction()
        {
        }

        public virtual void ExecuteHInstruction()
        {
        }

        public virtual void ExecuteLRInstruction()
        {
        }

        public virtual void ExecutePDInstruction()
        {
        }

        public virtual void ExecuteSRInstruction()
        {
        }
    }
}
